/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package game;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.io.IOException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Christian Friedli
 */

/*
 * To change this template, choose Tools | Templates and open the template in
 * the editor.
 */
public class Spiel implements Serializable, Runnable {

    private static List<Spieler> SpielerListe = new ArrayList<Spieler>();
    final static int MAXSPIELER = 4;
    public static int aktuellerSpieler = 1;
    private Spieler[] Spieler;
    private Reihe Reihe[];
    public int anzahlKartenAufTisch = 0;
    int letzteRundeKarte = 15;
    String letzteRunde = "letzte Runde";
    GemischterStapel GemischterStapel;
    boolean letzteRundekarteGezogen = false;
    boolean spielEnde = false;
    boolean rundeEnde = false;
    int anzahlAktiverReihen = 4;
    int anzahlAktiverVollerReihen = 0;
    boolean stapelkarteGezogen = false;
    Farbkarte gezogeneKarte;

    public static void main(String[] args) {


        
        
        Thread thSpiel = new Thread(new Spiel());
        thSpiel.start();
        try {
            System.in.read();
        } catch (IOException ex) {
            Logger.getLogger(Spiel.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            thSpiel.join();
        } catch (InterruptedException ex) {
            Logger.getLogger(Spiel.class.getName()).log(Level.SEVERE, null, ex);
        }

        // System.out.println("Spiel ENDE");
    }

    public void GameMain() {
        // Spiel vorbereiten
        
        // Anlegen der Spieler
        Spieler = new Spieler[MAXSPIELER + 1];
        for (int i = 1; i <= MAXSPIELER; i++) {
            Spieler[i] = new Spieler();
            SpielerListe.add(Spieler[i]);
        }

        // Spieler erzeugen
        Spieler[1] = new Spieler("Yanick", false, 1);
        SpielerListe.add(Spieler[1]);
        Spieler[2] = new Spieler("Tim", false, 2);
        SpielerListe.add(Spieler[2]);
        Spieler[3] = new Spieler("Sebi", false, 3);
        SpielerListe.add(Spieler[3]);
        Spieler[4] = new Spieler("Christian", false, 4);
        SpielerListe.add(Spieler[4]);

        // Reihenkarten legen - Reihenobjekte erstellen;       
        Reihe = new Reihe[4 + 1];
        for (int i = 1; i <= 4; i++) {
            Reihe[i] = new Reihe();
        }
        alleReihenAktivieren();

        // Kartenstapel vorbereiten
        GemischterStapel = new GemischterStapel();
        startFarbkartenVerteilen();
        System.out.println("\nSpiel start\n************\n");       
        alleSpielerAktivieren();
        
        aktuellerSpieler = 1;

        
        while (spielEnde == false) {

            ausgabeFarbkartenSpieler(aktuellerSpieler);

            //         ausgabeReihenkarten();
            Farbkarte[][] reihenArray;
            reihenArray = reihenkartenToArray();
            ausgabeReihenkarten2(reihenArray);

            int auswahl = stapelkarteOderReihe();

            if (auswahl == 1) {
                // Karte vom Stapel nehmen und einer Reihe hinzufügen
                gezogeneKarte = karteAufnehmen(aktuellerSpieler);
                System.out.println("Gezogene Karte: " + gezogeneKarte);
                // Nur für test für eingabe auf Konsole
                int reihe = farbkarteAufReihe();

                // Schleife nur zu test zwecken, sollte in GUI abgefangen werden
                while (false == karteAufReiheLegen(gezogeneKarte, reihe)) {
                    reihe = farbkarteAufReihe();
                }

            } else {
                // Reihe wählen
                int gewaehlteReihe = reiheWahlen();

                // Reihe aufnehmen! 
                while (reiheAufnehmen(gewaehlteReihe) == false) {
                    gewaehlteReihe = reiheWahlen();
                }
            }
        }
    }

    // Methode um jedem Spieler eine Farbkarte zu zuteieln
    // Jeder Spieler erhält einen andere Farbkarte
    // Start Farbkarte Spieler 1
    public void startFarbkartenVerteilen() {
        // Start Farbkarte Spieler 1
        Farbkarte k1 = GemischterStapel.karteAufnehmen();
        GemischterStapel.letzteKarteLöschen();
        System.out.println("Start Farbkarte Spieler 1: " + k1.toString());
        Spieler[1].karteAufnehmen(k1);
        // Kartenwert in einen String umwandeln um in anschliessend verlgeichen
        // zu könnene
        String s1 = k1.getFarbe();

        // Start Farbkarte Spieler 2
        Farbkarte k2 = GemischterStapel.karteAufnehmen();
        GemischterStapel.letzteKarteLöschen();
        String s2 = k2.getFarbe();
        // ist die aufgenommene Karte die gleich wie die Karte von Spieler 1
        // wird solange eine neue Karte gezogen, bis eine anders farbige Karte 
        // gezogen wurde
        while (s2.equals(s1)) {
            k2 = GemischterStapel.neueKarte(k2);
            GemischterStapel.letzteKarteLöschen();
            s2 = k2.getFarbe();
        }
        // Karte Spieler 2 übergeben
        Spieler[2].karteAufnehmen(k2);
        System.out.println("Start Farbkarte Spieler 2: " + k2.toString());

        // Start Farbkarte für Spieler 3
        Farbkarte k3 = GemischterStapel.karteAufnehmen();
        String s3 = k3.getFarbe();
        GemischterStapel.letzteKarteLöschen();
        // ist die aufgenommene Karte die gleich wie die Karte von Spieler 1 und 2
        while (s3.equals(s1) || s3.equals(s2)) {
            k3 = GemischterStapel.neueKarte(k3);
            GemischterStapel.letzteKarteLöschen();
            s3 = k3.getFarbe();
        }
        System.out.println("Start Farbkarte Spieler 3: " + k3.toString());
        // Karte Spieler 3 übergeben  
        Spieler[3].karteAufnehmen(k3);

        // Start Farbkarte für Spieler 4
        Farbkarte k4 = GemischterStapel.karteAufnehmen();
        String s4 = k4.getFarbe();
        GemischterStapel.letzteKarteLöschen();
        // ist die aufgenommene Karte die gleich wie die Karte von Spieler 1, 2 und 3
        while (s4.equals(s1) || s4.equals(s2) || s4.equals(s3)) {
            k4 = GemischterStapel.neueKarte(k4);
            GemischterStapel.letzteKarteLöschen();
            s4 = k4.getFarbe();
        }
        System.out.println("Start Farbkarte Spieler 4: " + k4.toString());
        // Karte Spieler 4 übergeben  
        Spieler[4].karteAufnehmen(k4);
    }

    // Methode um Karte vom Stapel zu nehmen
    // Es wird eine Karte vom Stapel genommen und geprüft ob es die Letzte Runde
    // Karte war
    // Es wird kontrolliert, ob es Reihen gibt welche noch nicht voll ist
    // Wenn all Reihen voll sind, gibt die Methode null zurück 
    public Farbkarte karteAufnehmen(int aktuellerSpieler) {
        if (anzahlAktiverVollerReihen() == 4) {
            // aktion nichtmöglich
            gezogeneKarte = null;
        } else {
            gezogeneKarte = GemischterStapel.karteAufnehmen();
            GemischterStapel.letzteKarteLöschen();

            // Ist die gezogene Karte letzte Rundekarte? Stapelgrösse 15?
            if (GemischterStapel.stapelGroesse() == letzteRundeKarte) {
                letzteRundekarteGezogen = true;
                System.out.println(letzteRunde);
            }
        }
        stapelkarteGezogen = true;
        return gezogeneKarte;
    }

    // Methode um die vom Stapel genommene Farbkarte einer Reihe zu zuweisen.
    // Es wird geprüft ob die Karte auf die angegeben Reihe gelegt werden kann.
    // Wenn ja wird Karte auf die Reihe gelegt und der nächste Spieler aufgerufen
    // Wenn nein, wird false zurück gegeben und der Spieler muss eine andere 
    // Reihe wählen
    public boolean karteAufReiheLegen(Farbkarte gezogeneKarte, int reihe) {
        System.out.println("Spieler " + aktuellerSpieler + ": Karte auf eine Reihe legen!");
        boolean aktionMoeglich;
        if (checkKarteAufReihe(reihe) == false) {
            // Aktion nicht möglich   
            aktionMoeglich = false;
        } else {
            // Karta auf die gewähle Reihe legen
            Reihe[reihe].karteHinzufügen(gezogeneKarte);
            stapelkarteGezogen = false;
            aktuellerSpieler = nextPlayer(aktuellerSpieler);
            System.out.println("****************************Next Player********************");
            aktionMoeglich = true;
        }
        return aktionMoeglich;
    }

    // Methode um eine Reihe aufzunehmen
    // Die Reihe wird aufgenommen und die enthaltenen Karten dem Spieler übergeben
    // Der Spieler wird inaktiv gesetzt.
    // Es wird überprüft ob die Reihe aktiv ist und mindestens ein Karte enthält
    // Der Spieler muss aktiv sein. Wenn nicht wird false zurück gegeben.
    public boolean reiheAufnehmen(int gewaehlteReihe) {
        boolean aktionMoeglich;
        if (Reihe[gewaehlteReihe].reiheAktiv == false && Reihe[gewaehlteReihe].reiheGroesse() == 0 && true == Spieler[aktuellerSpieler].IstAktiv()) {
            aktionMoeglich = false;
        } else {
            aktionMoeglich = true;
            // Reihe dem Spieler übergeben
            //Groesse der aufgenommen Reihe
            int GroesseStapel = Reihe[gewaehlteReihe].reiheGroesse();
            // Alle Reihenkarten dem Spieler übergeben
            for (int i = 0; i < GroesseStapel; i++) {
                Farbkarte karte = Reihe[gewaehlteReihe].karteVonReihe(i);
                Spieler[aktuellerSpieler].karteAufnehmen(karte);
            }
            Reihe[gewaehlteReihe].alleKartenLöschen();
            System.out.println("Stapel aufgenommen! \n");
            // Spieler inaktiv setzten
            Spieler[aktuellerSpieler].setIstAktiv(false);

            // Sind noch aktive Spieler vorhanden? Hat es noch aktive Reihenkarten? 
            // Hinweis: Wenn es noch aktive Reihen hat, hat es auch noch aktive Spieler
            anzahlAktiverReihen = anzahlAktiverReihen();
            if (anzahlAktiverReihen > 0) {
                // Es hat noch aktive Reihen / Spieler
                aktuellerSpieler = nextPlayer(aktuellerSpieler);
                System.out.println("****************************Next Player********************");
            } else {
                // Es hat keine aktiven Reihen / Spieler mehr
                // Wurde die letzte Rundekarte bereits gezogen?
                if (letzteRundekarteGezogen == true) {
                    // JA, letzte Rundekarte wurde gezogen
                    // ****************** SPIEL ENDE *******************
                    System.out.println("*************Spiel ENDE****************");
                    spielEnde = true;
                    // Rangliste anzeigen
                    punkteDerSpielerAusgeben();
                    // zur kontrolle ausgabe der Karten
                    ausgabeFarbkartenAllerSpieler();

                } else {
                    // NEIN, letzte Rundekarte wurde noch nicht gezogen
                    // Runde ist zuende
                    System.out.println("****************Runden ENDE***************");
                    ausgabeFarbkartenAllerSpieler();

                    // nächster Spieler
                    aktuellerSpieler = nextPlayer(aktuellerSpieler);
                    // alle Spieler aktivieren
                    alleSpielerAktivieren();

                    // alle Reihen aktivieren
                    alleReihenAktivieren();
                    anzahlAktiverReihen = 4;
                    anzahlAktiverVollerReihen = 0;
                    rundeEnde = true;
                }
            }
        }
        return aktionMoeglich;
    }

    // Zu testzwecken
    // Wenn man eine Reihe aufnehmen möchte
    public int reiheWahlen() {
        Scanner ReiheAuswaehlen = new Scanner(System.in);
        System.out.println("Spieler " + aktuellerSpieler + ": Reihe Aufnehmen! Geben Sie eine Reihe von 1 bis 4 ein: ");
        int gewaehlteReihe = ReiheAuswaehlen.nextInt();
        return gewaehlteReihe;
    }

    // Methode prüft ob die Reihe aufgenommen werden kann
    // mindestens eine Karte und Reihe muss aktiv sein!
    public boolean checkReiheAufnehmen(int gewaehlteReihe) {
        boolean check = false;
        int groesse = Reihe[gewaehlteReihe].reiheGroesse();
        if (groesse > 0) {
            check = true;
        } else {
            System.out.println("Reihe ungültig! Andere Reihe wählen!");
        }
        return check;
    }

    // Methode prüft ob die gezogenenFarbkarte auf die gewählte Reihe
    // gelegt werden darf
    // Reihe muss aktiv sein aber nicht voll (< 3 Karten)
    public boolean checkKarteAufReihe(int gewaehlteReihe) {
        boolean check = false;
        if (gewaehlteReihe != 1 && gewaehlteReihe != 2 && gewaehlteReihe != 3 && gewaehlteReihe != 4) {
            System.out.println("Falsche Eingabe!");
        } else {
            // Reihe muss aktive sein, darf aber nicht voll sein
            if (Reihe[gewaehlteReihe].reiheAktiv == true && Reihe[gewaehlteReihe].ReiheVoll() == false) {
                check = true;
            } else {
                System.out.println("Die Reihe ist voll oder nicht aktiv! Andere Reihe wählen");
            }
        }
        return check;
    }

    // Methode um abzufagen ob Spieler eine Karte vom Stapel nehmen möchte, oder
    // eine Reihe aufnehmen möchte
    public int stapelkarteOderReihe() {
        System.out.println("Spieler " + aktuellerSpieler + ": Karte vom Stapel (1) oder Reihe (2) aufnehmen?");
        Scanner auswaehlen = new Scanner(System.in);
        int auswahl = (int) auswaehlen.nextInt();
        while ((auswahl != 1) && (auswahl != 2)) {
            System.out.println("Ihre auswahlt " + auswahl + " ist ungültig. Neue Eingabe: ");
            auswahl = auswaehlen.nextInt();
        }
        if (auswahl == 2 && anzahlKartenAufTisch() == 0) {
            System.out.println("Es gibt keine Reihe zum Aufnehme! Bitte nehmen Sie eine Karte vom Stapel");
            auswahl = 1;
        }

        if (auswahl == 1 && anzahlAktiverReihen() == anzahlAktiverVollerReihen()) {
            System.out.println("Es sind alle Reihen voll!! Sie müssen eine Reihe aufnehmen!");
            auswahl = 2;
        }

        return auswahl;
    }

    public int farbkarteAufReihe() {
        System.out.println("Spieler " + aktuellerSpieler + ": Reihe wählen, auf welche Sie die Karte legen möchten (1 bis 4): ");
        Scanner ReiheAuswaehlen = new Scanner(System.in);
        int gewaehlteReihe = ReiheAuswaehlen.nextInt();
        return gewaehlteReihe;
    }

    public int anzahlAktiverReihen() {
        anzahlAktiverReihen = 0;
        for (int i = 1; i <= 4; i++) {
            if (Reihe[i].reiheAktiv == true) {
                anzahlAktiverReihen++;
            }
        }
        return anzahlAktiverReihen;
    }

    public int anzahlAktiverVollerReihen() {
        anzahlAktiverVollerReihen = 0;
        for (int i = 1; i <= 4; i++) {
            if (Reihe[i].ReiheVoll() == true) {
                anzahlAktiverVollerReihen++;
            }
        }
        return anzahlAktiverVollerReihen;
    }

    // Methode um alle Reihen zu aktivieren
    public void alleReihenAktivieren() {
        for (int i = 1; i <= 4; i++) {
            Reihe[i].ReiheAktivieren();
        }
    }

    // Methode um alle Spieler zu aktivieren
    public void alleSpielerAktivieren() {
        for (int i = 1; i <= MAXSPIELER; i++) {
            Spieler[i].setIstAktiv(true);
        }
    }

    // Nur für Test
    // Methode um die Punkte aller 
    public void punkteDerSpielerAusgeben() {

        int PunkteSpieler1 = Spieler[1].punkteZählen();
        int PunkteSpieler2 = Spieler[2].punkteZählen();
        int PunkteSpieler3 = Spieler[3].punkteZählen();
        int PunkteSpieler4 = Spieler[4].punkteZählen();

        System.out.println("Spieler 1 hat " + PunkteSpieler1 + " Punkte!");
        System.out.println("Spieler 2 hat " + PunkteSpieler2 + " Punkte!");
        System.out.println("Spieler 3 hat " + PunkteSpieler3 + " Punkte!");
        System.out.println("Spieler 4 hat " + PunkteSpieler4 + " Punkte!");

        //new writehighscore(Spieler);

    }

    public void ausgabeFarbkartenAllerSpieler() {
        for (int spieler = 1; spieler <= 4; spieler++) {
            System.out.println("Die Karte von Spieler " + spieler + " :");
            int i = Spieler[spieler].aufgenommeneKarten.size();
            for (int a = 0; a < i; a++) {
                Farbkarte tmp = Spieler[spieler].aufgenommeneKarten.get(a);
                System.out.print(tmp + "  ");
            }
        }
        System.out.println();
    }

    public void ausgabeFarbkartenSpieler(int aktuellerSpieler) {
        System.out.print("Die Karte von Spieler " + aktuellerSpieler + ": ");
        int i = Spieler[aktuellerSpieler].aufgenommeneKarten.size();
        for (int a = 0; a < i; a++) {
            Farbkarte tmp = Spieler[aktuellerSpieler].aufgenommeneKarten.get(a);
            System.out.print(tmp + "  ");
        }
        System.out.println();
        System.out.println();
    }

    public void ausgabeReihenkarten() {
        for (int reihe = 1; reihe <= 4; reihe++) {

            if (Reihe[reihe].reiheAktiv == true) {
                System.out.println("Karten auf Reihe " + reihe + " :");
                int i = Reihe[reihe].Reihe.size();
                for (int a = 0; a < i; a++) {
                    Farbkarte karte = Reihe[reihe].karteVonReihe(a);
                    System.out.print(karte + "  ");
                }
                System.out.println();
            }
        }
    }

    public void ausgabeReihenkarten2(Farbkarte Farbkarte[][]) {
        for (int reihe = 1; reihe <= 4; reihe++) {
            if (Reihe[reihe].reiheAktiv == true) {
                System.out.print("Karten von Reihe " + reihe + ": ");
                for (int karte = 0; karte < Reihe[reihe].reiheGroesse(); karte++) {
                    String k = Farbkarte[reihe - 1][karte].getFarbe();
                    System.out.print(k + " ");
                }
                System.out.println();
            }
        }
        System.out.println();
    }

    // Methode welche ein Array mit den Farbkarten welche auf den Reihenkarte zurück gibt
    public Farbkarte[][] reihenkartenToArray() {
        Farbkarte[][] reiheArray = new Farbkarte[4][3];
        for (int reihe = 1; reihe <= 4; reihe++) {

            for (int karte = 0; karte < Reihe[reihe].reiheGroesse(); karte++) {
                Farbkarte karteVonReihe = Reihe[reihe].karteVonReihe(karte);
                reiheArray[reihe - 1][karte] = karteVonReihe;
            }
        }
        return reiheArray;
    }

    // Methode um die von der Reihe aufgenommenen Farbkarte dem Spieler zu 
    // zuteile.
    // Die Aufgenommene Reihe wird geschlöscht und inaktiv gesetzt
    public void reiheSpielerUbergeben(int gewaehlteReihe) {

        //Groesse der aufgenommen Reihe
        int GroesseStapel = Reihe[gewaehlteReihe].reiheGroesse();
        // Alle Reihenkarten dem Spieler übergeben
        for (int i = 0; i < GroesseStapel; i++) {
            Farbkarte karte = Reihe[gewaehlteReihe].karteVonReihe(i);
            Spieler[aktuellerSpieler].karteAufnehmen(karte);
        }
        Reihe[gewaehlteReihe].alleKartenLöschen();
    }

    // Gibt die Anzahl der Karten auf dem Tisch aus, Respekitve die Karten auf 
    // einer Reihe
    public int anzahlKartenAufTisch() {
        anzahlKartenAufTisch = 0;
        for (int i = 1; i <= 4; i++) {
            int Groesse = Reihe[i].reiheGroesse();
            anzahlKartenAufTisch = anzahlKartenAufTisch + Groesse;
        }
        return anzahlKartenAufTisch;
    }

    // Methode um den nächste aktiven Spieler zu ermitteln
    public int nextPlayer(int aktuellerSpieler) {
        int nextPlayer = 0;
        switch (aktuellerSpieler) {
            case 1:
                if (Spieler[2].IstAktiv()) {
                    nextPlayer = 2;
                    break;
                } else if (Spieler[3].IstAktiv()) {
                    nextPlayer = 3;
                    break;
                } else if (Spieler[4].IstAktiv()) {
                    nextPlayer = 4;
                    break;
                } else {
                    nextPlayer = 1;
                    break;
                }
            case 2:
                if (Spieler[3].IstAktiv()) {
                    nextPlayer = 3;
                    break;
                } else if (Spieler[4].IstAktiv()) {
                    nextPlayer = 4;
                    break;
                } else if (Spieler[1].IstAktiv()) {
                    nextPlayer = 1;
                    break;
                } else {
                    nextPlayer = 2;
                    break;
                }
            case 3:
                if (Spieler[4].IstAktiv()) {
                    nextPlayer = 4;
                    break;
                } else if (Spieler[1].IstAktiv()) {
                    nextPlayer = 1;
                    break;
                } else if (Spieler[2].IstAktiv()) {
                    nextPlayer = 2;
                    break;
                } else {
                    nextPlayer = 3;
                    break;
                }
            case 4:
                if (Spieler[1].IstAktiv()) {
                    nextPlayer = 1;
                    break;
                } else if (Spieler[2].IstAktiv()) {
                    nextPlayer = 2;
                    break;
                } else if (Spieler[3].IstAktiv()) {
                    nextPlayer = 3;
                    break;
                } else {
                    nextPlayer = 4;
                    break;
                }
        }
        return nextPlayer;
    }

    public boolean stapelkarteGezogen() {
        return stapelkarteGezogen;
    }

    public Farbkarte gezogeneKarte() {
        return gezogeneKarte;
    }

    public boolean spielEnde() {
        return spielEnde;
    }

    @Override
    public void run() {
        GameMain();
    }


}